<template>
    <div>
        <van-overlay v-if="visibleModal" class="overlay" :show="visibleModal">
            <div class="app_face">
                <p class="title">{{$t("face_recognition_check_in")}}<span v-show="showClose" @click="closePop()" style="position: absolute;right: 20px"><van-icon name="cross" /></span></p> <!-- 人脸识别 -->
                <div class="wrapper"  style="padding:20px 10px;" @click.stop>
                    <div id="fa" class="video-box" :style="'width: ' + screenWidth + 'px; height: ' + clientHeight + 'px;'">
                        <video id="video" :width="screenWidth" :height="clientHeight" preload autoplay loop muted playsinline="true" webkik-playsinline="true">
                            <!-- <source type="video/mp4"> -->
                        </video>
                        <canvas id="canvas" :width="screenWidth" :height="clientHeight"></canvas>
                    </div>
                    <canvas id="screenshotCanvas" :width="screenWidth" :height="clientHeight"></canvas>
                    <div v-if="needToCollect" style="padding-top: 20px;text-align: center;">
                        <div style="padding-top: 20px;text-align: center;color:#F59A23">{{$t("no_facial")}}</div> <!-- 人脸信息未采集 -->
                        <div style="text-align:center;margin-top:15px">
                            <van-button round color="#075ebb" size="small" style="padding: 0 20px;" @click="onCollect">{{$t("facial_information_collection")}}</van-button> <!-- 人脸信息采集 -->
                        </div>
                    </div>
                    <div v-else-if="!recognitionSuc && busId" style="padding-top: 20px;text-align: center;color:#F59A23">{{$t("tips1_recognition_check_in")}}</div> <!-- 请将人脸对准摄像头-->
                    <div v-else-if="!busId" style="padding-top: 20px;text-align: center;">
                        <div style="padding-top: 20px;text-align: center;color:#F59A23">{{$t("abnormal_facial_parameters")}}</div> <!-- 获取人脸参数异常，请点击刷新后重试 -->
                        <div style="text-align:center;margin-top:15px">
                            <van-button round color="#075ebb" size="small" style="padding: 0 20px;" @click="refresh">{{$t("button_refresh")}}</van-button> <!-- 刷新 -->
                        </div>
                    </div>
                    <div v-else>
                        <div style="padding-top: 20px;text-align: center;color:#F56C6C">{{$t("tips2_please_recognition")}}</div> <!-- 人脸识别失败,请重新识别 -->
                        <div style="text-align:center;margin-top:15px">
                            <van-button v-if="!examination" round type="default" size="small" style="margin-right: 30px;padding: 0 20px;" @click="cancelDistinguish">{{$t("circle_kg_13")}}</van-button> <!-- 取消识别 -->
                            <van-button round color="#075ebb" size="small" @click="reIdentification">{{$t("Re_identification")}}</van-button> <!-- 重新识别 -->
                        </div>
                    </div>
                    <slot name="down"></slot>
                </div>
            </div>
        </van-overlay>
    </div>
</template>

<script>
import {Overlay, Button, Toast} from 'vant';

import '@/utils/tracking/tracking.js';
import '@/utils/tracking/face-min.js';
export default {
    name: 'faceModal',
    components: {
        [Button.name]: Button,
        [Overlay.name]: Overlay,
        Toast
    },
    props: {
        visibleModal: { // 是否显示人脸识别弹窗
            type: Boolean,
            default: false
        },
        showClose: { // 是否显示关闭按钮
            type: Boolean,
            default: false
        },
        busId: { // 业务ID
            type: [Number, String],
            default: null
        },
        distinguishType: {
            type: String,
            default: ''
        },
        firIdentificationWay: {
            type: String, // 识别方式，QR_CODE: 扫码人脸识别（二维码 + APP）, APP: 移动端人脸识别, WEB: PC端人脸识别
            default: 'APP'
        },
        // 是否为考试中
        examination: {
            type: Boolean,
            default: false
        },
        // 识别节点
        ufrId: { // 识别节点
            type: [Number, String],
            default: 0
        },
        busOpeType: { // 业务操作类型, 0-签到, 1-签退（目前只有日程打卡使用）
            type: [Number, String],
            default: null
        },
        busParams: {
            type: Object,
            default: () => ({})
        }
    },
    data() {
        return {
            visibleModal1: false,
            base64: null,
            faceStuas: null,
            recognitionSuc: false,
            videoEl: {},
            video: null,
            screenshotCanvas: null,
            screenWidth: 300,
            clientHeight: 362,
            uploadLock: true, // 上传锁
            trackerTask: null, // 人脸识别任务
            needToCollect: false // 未采集人脸，默认已采集 需要采集
        };
    },
    watch: {
        visibleModal(newVal) {
            if (newVal) {
                this.openModal();
            }
            this.visibleModal1 = newVal;
        },
        visibleModal1(val) {
            this.$parent.visibleModal = val;
        }
    },
    methods: {
        cancelDistinguish() {
            this.visibleModal1 = false;
            this.recognitionSuc = false;
            this.closeCamera();
            this.$emit('closeFace');
        },
        // 直播关闭按钮关闭人脸弹窗
        closePop() {
            this.$emit('closeFace');
        },
        // 重新识别
        reIdentification() {
            this.openModal();
        },
        // 关闭摄像头
        closeCamera() {
            if (!this.visibleModal) return;
            if (typeof window.stream === 'object') {
                if (this.videoEl.srcObject) {
                    this.videoEl.srcObject = null;
                }
                window.stream.getTracks().forEach((track) => track.stop()); // 停止侦测
            }
            if (this.video.srcObject) {
                this.video.srcObject.getTracks()[0].stop();
            }
            if (this.trackerTask) {
                this.trackerTask.stop();
            }
        },
        screenshotAndUpload(context, canva) {
            // 上锁避免重复发送请求
            this.uploadLock = false;
            // 绘制当前帧图片转换为base64格式
            const canvas = document.getElementById('canvas');
            const video = this.video;
            const ctx = canvas.getContext('2d');
            // 调整canvas的实际像素数防止图片拉伸
            let devicePixelRatio = window.devicePixelRatio || 1;
            let backingStoreRatio = context.webkitBackingStorePixelRatio ||
                context.mozBackingStorePixelRatio ||
                context.msBackingStorePixelRatio ||
                context.oBackingStorePixelRatio ||
                context.backingStorePixelRatio || 1;
            let ratio = devicePixelRatio / backingStoreRatio;
            canvas.width = canvas.clientWidth * ratio;
            canvas.height = canvas.clientHeight * ratio;
            // 计算画布的宽高比和视频的宽高比
            let canvasAspectRatio = canvas.width / canvas.height;
            let videoAspectRatio = video.videoWidth / video.videoHeight;
            // 计算调整后的画布尺寸，使其与视频尺寸保持一致
            if (videoAspectRatio > canvasAspectRatio) {
                canvas.height = canvas.width / videoAspectRatio;
            } else {
                canvas.width = canvas.height * videoAspectRatio;
            }
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            const base64Img = canvas.toDataURL('image/jpeg');
            // 使用 base64Img 请求接口即可
            let data = {
                ufgPath: base64Img,
                busId: this.busId,
                userFaceTypeEnum: this.distinguishType,
                firIdentificationWay: this.firIdentificationWay,
                ufrId: this.ufrId,
                busOpeType: this.busOpeType,
                busParams: this.busParams
            };
            context.clearRect(0, 0, canva.width, canva.height);
            // 获取用户人脸采集信息
            this.$axios.get('/app/api/trainee/user-face-gather/getDetail').then(res => {
                if (res.data) {
                    if (res.data.ufgApprovalStatus === 'PENDING' || res.data.ufgApprovalStatus === 'DECLINED') {
                        this.$emit('takingError');
                        this.uploadLock = true;
                        Toast({
                            message: this.$t('face_verification_in_progress'), // 用户人脸采集信息审核中或审核未通过
                            duration: 3000,
                            forbidClick: true
                        });
                    } else if (res.data.ufgApprovalStatus === 'APPROVED') {
                        this.$axios.post(`/app/api/trainee/user-face-gather/compareFaceFeature`, data).then(res => {
                            if (res.data) {
                                this.recognitionSuc = false;
                                this.$emit('takePictures');
                            } else {
                                this.recognitionSuc = true;
                            }
                        }).catch((err) => {
                            let {data, status} = err.response;
                            this.$emit('takingError');
                            this.uploadLock = true;
                            Toast({
                                message: this.$t('tips2_please_recognition') + data.errMsg,
                                duration: 3000,
                                forbidClick: true
                            });
                        });
                    }
                } else {
                    this.needToCollect = true;
                    Toast({
                        message: this.$t('no_facial'),
                        duration: 3000,
                        forbidClick: true
                    });
                }
            });
        },
        openModal() {
            this.faceStuas = null;
            this.uploadLock = true;
            this.needToCollect = false;
            this.faceModal();
        },
        faceModal() {
            if (this.trackerTask) {
                this.closeCamera();
            }
            this.$nextTick(() => {
                this.video = document.getElementById('video');
                this.screenshotCanvas = document.getElementById('screenshotCanvas');
                const canvas = document.getElementById('canvas');
                const context = canvas.getContext('2d');
                // 固定写法
                /*eslint-disable */
                const tracker = new tracking.ObjectTracker('face');//检测人脸
                tracker.setInitialScale(4);
                tracker.setStepSize(2);
                tracker.setEdgesDensity(0.1);

                // 取消第三个参数camera：true，防止闪屏
                this.trackerTask = tracking.track('#video', tracker, { });
                this.videoEl.srcObject = window.stream;
                const constraints = {
                    video: { width: this.screenWidth, height: this.clientHeight , facingMode: 'user'}
                    // audio: true
                };
                const promise = navigator.mediaDevices.getUserMedia(constraints); // h5 新的API
                const _this = this;
                promise.then(function(MediaStream) {
                    _this.video.srcObject = MediaStream;
                    _this.video.play();
                }).catch(function(PermissionDeniedError) {
                    if (PermissionDeniedError.name === 'NotAllowedError' && PermissionDeniedError.message==='Permission denied') {
                        _this.$emit('takingError');
                        Toast({
                            message: this.$t('face_user_refuses_authorization_wx'), // 用户拒绝授权，影响后续功能使用，请退出公众号重新进入获取授权
                            duration: 3000,
                            forbidClick: true
                        });
                        _this.$router.go(-1)
                    } else if(PermissionDeniedError.name === 'NotAllowedError' ) {
                        _this.$emit('takingError');
                        Toast({
                            message: this.$t('face_user_refuses_authorization'), // 用户拒绝授权，影响后续功能使用，请重新进入获取授权
                            duration: 2000,
                            forbidClick: true
                        });
                        _this.$router.go(-1)
                    }
                });
                // 2s后开始检测人脸，防止识别一闪而过
                setTimeout(() => {
                    tracker.on('track', function(event) {
                        // 检测出人脸 绘画人脸位置
                        event.data.forEach(function(rect) {
                            if (_this.uploadLock && _this.busId) {
                                // 上传图片
                                _this.screenshotAndUpload(context,canvas);
                            }
                        });
                    });
                }, 2000);
            });
        },
        /**
         * 刷新
         */
        refresh() {
            this.busId = window.localStorage.getItem('face_busId');
            if (this.busId) {
                this.closeCamera();
                this.openModal();
            }
        },
        /**
         * 去采集人脸
         */
        onCollect() {
            // 关闭人脸识别
            this.cancelDistinguish();
            // 跳转到人脸采集页面
            this.$router.push({ path: '/faceInfoPage' });
        }
    },
    beforeDestroy() {
        this.closeCamera();
    }
};
</script>

<style lang="less" scoped>
/deep/.face-class .el-dialog__body {
  padding: 10px !important;
}
/deep/.van-button--primary{
    background-color: #1989FA;
    border: 1px solid #1989FA;
    padding: 0 40px;
    text-align: center;
}
.overlay{
  z-index: 999;
}
 /* 绘图canvas 不需显示隐藏即可 */
#screenshotCanvas{
  display: none;
}
.video-box{
  background: #000;
  position: relative;
  width: 440px;
  height: 452px;
}
video,canvas{
  position: absolute;
  top: 0;
  left: 0;
  // border: #000000 5px solid;
}
.app_face{
    width: 320px;
    margin:auto;
    background: #fff;
    margin-top:80px;
    border-radius: 5px;
    position: relative;
}
.title{
    height: 36px;
    background-color: #F2F2F2;
    line-height: 36px;
    text-align: center;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
}
</style>
